/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
* AnnealIModel.java
*
* Created on December 29, 2007, 10:41 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
 */
package gui.genomemap.inputModel;

import genomemap.data.RFLPImputation;

import gui.genomemap.inputModel.optOperations.AnnealOptionalOperModel;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToOne;

/**
 *
 * @author stewari1
 */
@Entity
public class AnnealIModel extends InputModel implements java.io.Serializable {


    // GHood related

    /** Field description */
    private int gIterationLimit = 150;

    /** Field description */
    private double gConvgEpsilon = 1.0E-4;

    /** Field description */
    @OneToOne(cascade = CascadeType.PERSIST)
    private RFLPImputation rflpImputation = new RFLPImputation();

    /** Field description */
    private int lhoodType = 0;

    /**
     *  TOTAL # OF ITERATIONS TO BE TRIED IN THE ENTIRE ANNEALING MACHINE.
     *  AFTER WHICH THE MACHINE IS STOPPED IF NOT CONVERGED ALREADY.
     */
    private int MASTER_ITER_COUNT = 5000;

    /**
     * TOTAL # OF ITERATIONS TO BE TRIED UNDER A TEMPERATURE,
     * AFTER WHICH THE TEMPERATURE IS REDUCED BY FORCE IF NOT SKIPPED ALREADY
     */
    private int TEMP_ITER_COUNT = 100;

    /**
     * STARTING TEMPERATURE
     */
    private double START_TEMP = 10.0;

    /**
     * TEMPERATURE FRICTION
     */
    private double TEMP_FRICTION = 0.5;

    /**
     *  MAXIMUM UNBEATEN COUNT
     */
    private int MAX_UNBEATEN_COUNT = 50;

    /**
     * MAXIMUM BEATEN COUNT
     */
    private int MAX_BEATEN_COUNT = 50;

    /**
     * percent: % of liklelihood improvement considered
     */
    private double percent = 0.01;

    /** Field description */
    @OneToOne(cascade = CascadeType.PERSIST)
    private AnnealOptionalOperModel optionalOperModel = new AnnealOptionalOperModel();

    /**
     * true: if simulated annealing has converged
     */
    private boolean converged;

    /** Creates a new instance of AnnealIModel */
    public AnnealIModel() {}

    @Override
    public int hashCode() {

        return super.hashCode() + new Integer(gIterationLimit).hashCode()
               + new Double(gConvgEpsilon).hashCode() + getRflpImputation().hashCode()
               + new Integer(MASTER_ITER_COUNT).hashCode()
               + new Integer(TEMP_ITER_COUNT).hashCode()
               + new Integer(MAX_UNBEATEN_COUNT).hashCode() + new Double(percent).hashCode()
               + new Double(START_TEMP).hashCode() + new Double(TEMP_FRICTION).hashCode()
               + new Integer(lhoodType).hashCode() + new Integer(MAX_BEATEN_COUNT).hashCode();
    }

    /**
     * Note that <CODE>optionalOperModel</CODE> is not included in the <CODE>hashCode</CODE>
     * and <CODE>equals</CODE> implementation. This is to differentiate between the
     * core input setings that would require a fresh LHood computation from optional
     * operations which do not require a fresh LHood computation except for few
     * (SE computation if the accuracy wasn`t up to the required level).
     */
    @Override
    public boolean equals(Object obj) {

        if (obj instanceof AnnealIModel) {

            if (super.equals(obj)) {

                AnnealIModel inputModel = (AnnealIModel) obj;

                return (this.getGIterationLimit() == inputModel.getGIterationLimit())
                       && (this.getGConvgEpsilon() == inputModel.getGConvgEpsilon())
                       && (this.getLhoodType() == inputModel.getLhoodType())
                       && this.getRflpImputation().equals(inputModel.getRflpImputation());
            }

            return false;
        }

        return false;
    }

    public int getGIterationLimit() {
        return gIterationLimit;
    }

    public void setGIterationLimit(int iterationLimit) {
        this.gIterationLimit = iterationLimit;
    }

    public double getGConvgEpsilon() {
        return gConvgEpsilon;
    }

    public void setGConvgEpsilon(double convgEpsilon) {
        this.gConvgEpsilon = convgEpsilon;
    }

    public int getMASTER_ITER_COUNT() {
        return MASTER_ITER_COUNT;
    }

    public void setMASTER_ITER_COUNT(int MASTER_ITER_COUNT) {
        this.MASTER_ITER_COUNT = MASTER_ITER_COUNT;
    }

    public int getTEMP_ITER_COUNT() {
        return TEMP_ITER_COUNT;
    }

    public void setTEMP_ITER_COUNT(int TEMP_ITER_COUNT) {
        this.TEMP_ITER_COUNT = TEMP_ITER_COUNT;
    }

    public double getSTART_TEMP() {
        return START_TEMP;
    }

    public void setSTART_TEMP(double START_TEMP) {
        this.START_TEMP = START_TEMP;
    }

    public double getTEMP_FRICTION() {
        return TEMP_FRICTION;
    }

    public void setTEMP_FRICTION(double TEMP_FRICTION) {
        this.TEMP_FRICTION = TEMP_FRICTION;
    }

    public int getMAX_UNBEATEN_COUNT() {
        return MAX_UNBEATEN_COUNT;
    }

    public void setMAX_UNBEATEN_COUNT(int MAX_UNBEATEN_COUNT) {
        this.MAX_UNBEATEN_COUNT = MAX_UNBEATEN_COUNT;
    }

    public int getMAX_BEATEN_COUNT() {
        return MAX_BEATEN_COUNT;
    }

    public void setMAX_BEATEN_COUNT(int MAX_BEATEN_COUNT) {
        this.MAX_BEATEN_COUNT = MAX_BEATEN_COUNT;
    }

    public double getPercent() {
        return percent;
    }

    public void setPercent(double percent) {
        this.percent = percent;
    }

    public boolean isConverged() {
        return converged;
    }

    public void setConverged(boolean converged) {
        this.converged = converged;
    }

    public AnnealOptionalOperModel getOptionalOperModel() {
        return optionalOperModel;
    }

    public void setOptionalOperModel(AnnealOptionalOperModel optionalOperModel) {
        this.optionalOperModel = optionalOperModel;
    }

    public int getLhoodType() {
        return lhoodType;
    }

    public void setLhoodType(int lhoodType) {
        this.lhoodType = lhoodType;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {

        AnnealIModel annealIModel = new AnnealIModel();

        annealIModel.setLinkageGroup(this.getLinkageGroup());
        annealIModel.setOrderSet(this.getOrderSet());
        annealIModel.setMASTER_ITER_COUNT(this.getMASTER_ITER_COUNT());
        annealIModel.setTEMP_ITER_COUNT(this.getTEMP_ITER_COUNT());
        annealIModel.setSTART_TEMP(this.getSTART_TEMP());
        annealIModel.setTEMP_FRICTION(this.getTEMP_FRICTION());
        annealIModel.setMAX_UNBEATEN_COUNT(this.getMAX_UNBEATEN_COUNT());
        annealIModel.setMAX_BEATEN_COUNT(this.getMAX_BEATEN_COUNT());
        annealIModel.setPercent(this.getPercent());
        annealIModel.setGConvgEpsilon(this.getGConvgEpsilon());
        annealIModel.setGIterationLimit(this.getGIterationLimit());
        annealIModel.setRflpImputation(this.getRflpImputation());

        return annealIModel;
    }

    public RFLPImputation getRflpImputation() {
        return rflpImputation;
    }

    public void setRflpImputation(RFLPImputation rflpImputation) {
        this.rflpImputation = rflpImputation;
    }
}
